﻿using CommonModel.Field;
using CommonModel.Model;
using PtlSave.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PtlSave.Model
{
    /*
     * 表的相关描述 均基于涛思数据库
     */
    public class TableInfo
    {
        //超级表
        //表名称 表名最大长度为 192
        public string tableName {
            get
            {
                string tmpName = tableCfg.getFile_name();
                return "cj_" + tmpName.Substring(0, tmpName.LastIndexOf('.')).Replace(".", "_");
            }
        }
        //超级表所属所有子表
        public Dictionary<string, int> tableNames { get; set; } = null;
        //动态字段及其当前最大值
        public Dictionary<string, string> dynamic { get; set; } = null;
        //当前的最大层级数量
        public int layerNum { get; set; } = 3;
        //列，数据库应该有的
        //列的最大个数为1024，最小个数为2
        public Dictionary<int, ColumnInfo> columns { get; set; } = null;
        //初始已有5个默认字段
        public int colNum { get; set; } = 6;    //4个默认字段，2个tags
        //用于数据库保存是字段拼接
        public string columnsStr = "";
        public string columnsStrFull
        {
            get 
            {
                return columnsStr.ToUpper() + ",IP,PORT";
            }
        }
        //默认字段
        public Dictionary<int, ColumnInfo> columnsDft { get; set; } = null;
        //从数据库读取的字段配置明细
        public SchemaDocument tableCfg { get; set; } = null;

        public TableInfo(SchemaDocument tableCfg)
        {
            this.tableCfg = tableCfg;
            Init();
        }

        public void Init()
        {
            tableNames = new Dictionary<string, int>();
            columns = new Dictionary<int, ColumnInfo>();
            columnsDft = new Dictionary<int, ColumnInfo>()
            {
                { 0, new ColumnInfo(){ columnNameTaos = "ts", columnName = "ts", typeCfg = "TIMESTAMP"} },   //涛思数据库，固定必须包含要给TIMESTAMP字段ts
                { 1, new ColumnInfo(){ columnNameTaos = "c_from", columnName = "c_from", columnLen = 25, typeCfg = "NCHAR"} },   //ip:port
                { 2, new ColumnInfo(){ columnNameTaos = "c_paramId", columnName = "c_paramId", columnLen = 11, typeCfg = "UINT32"} },   //mysql表id，带上该配置，便于后续数据处理
                { 3, new ColumnInfo(){ columnNameTaos = "schema_name", columnName = "schema_name", columnLen = 50, typeCfg = "NCHAR"} }   //解析时获取的获取解析协议配置名称，便于后续分类查询等处理
            };
            colNum = columnsDft.Count + 2;
            dynamic = tableCfg.getDynamicParaDictionary();
            SetColumns();
        }

        private void SetColumns()
        {
            Dictionary<int, Object> dicts = tableCfg.getFieldDictionary();
            foreach (int key in dicts.Keys)
            {
                SetColumn(dicts[key], columns);
            }

            columnsStr = "";
            foreach (int key in columnsDft.Keys)
            {
                columnsStr = columnsStr + ("".Equals(columnsStr) ? "" : ",") + columnsDft[key].columnNameTaos;
            }
            foreach (int key in columns.Keys)
            {
                if (!columns[key].isParent)
                { 
                    columnsStr = columnsStr + ("".Equals(columnsStr) ? "" : ",") + columns[key].columnNameTaos;
                }
            }
        }

        /*
         * obj 行对象
         * columns 需要填充的行信息
         * layer 当前行层级
         * suffix 字段后缀，loop时，避免字段重复，且容易区分
         * loopIdx loop编号，写数据库时用
         * parentLoop 父层级的loop值
         */
        private void SetColumn(Object obj, Dictionary<int, ColumnInfo> columns, string suffix = "", int loopIdx = -1, string parentLoop = "")
        {
            if (obj is FieldSchema)
            {
                FieldSchema field = (FieldSchema)obj;
                if ("1".Equals(field.getIsSave()))
                {
                    //字段长度最大64，如果超过，创建表时会自动截取掉
                    string columnName = "c_" + field.getName() + field.getIndex() + ("".Equals(suffix) ? suffix : "_" + suffix);
                    columns.Add(columns.Count, new ColumnInfo() { parentLoop = parentLoop, loopIdx = loopIdx, layer = field.getLayer(), field = field, columnName = field.getName(), columnNameTaos = (columnName.Length > 64) ? columnName.Substring(0, 64) : columnName, columnLen = field.getSize(), typeCfg = field.type.ToString() });
                    colNum++;
                }
            }
            else if(obj is SchemaDictionary)
            {
                SchemaDictionary field = (SchemaDictionary)obj;
                if ("1".Equals(field.getIsSave()))
                { 
                    Dictionary<int, Object> dicts = (Dictionary<int, Object>)(field.getFieldDictionary());

                    //改成一个字段用分隔符分开（字段长度加长一些），不用多个字段，在动态loop的时候容易出问题
                    //父节点isParent为true
                    //字段长度最大64，如果超过，创建表时会自动截取掉
                    string columnName = "c_" + field.getName() + field.getIndex() + ("".Equals(suffix) ? suffix : "_" + suffix);
                    columns.Add(columns.Count, new ColumnInfo() { parentLoop = parentLoop, loopIdx = loopIdx, layer = field.getLayer(), isParent = true, field = field, columnName = field.getName(), columnNameTaos = (columnName.Length > 64) ? columnName.Substring(0, 64) : columnName, columnLen = field.getSize(), typeCfg = field.type.ToString() });

                    int loopThis = 1;   //循环
                    string loopStr = field.getLoop();
                    //如果是数值，则直接读取
                    if (CommonUtil.IsInt(loopStr))
                    {
                        loopThis = int.Parse(loopStr);
                    }
                    //如果是动态字段，则读取其默认（当前最大）值
                    else if(dynamic.ContainsKey(loopStr))
                    {
                        loopThis = int.Parse(dynamic[loopStr]);
                    }
                    for (int i = 0; i < loopThis; i++)
                    {
                        string suffixNext = field.getName() + field.getIndex() + "_" + i.ToString() + ("".Equals(suffix) ? "" : "_" + suffix);
                        foreach (int keyIn in dicts.Keys)
                        {
                            SetColumn(dicts[keyIn], columns, suffixNext, i, loopStr);
                        }
                    }
                }
            }
        }

        /*
         * 获取创建表（以超级表为模板创建数据表）语句
         */
        public string GetCreateTableSql(string tbName, string ip, string port)
        {
            return "CREATE TABLE IF NOT EXISTS " + tbName + " USING " + tableName + " (ip, port) TAGS ('" + ip + "', " + port + ")";
        }
        /*
         * 获取创建超级表语句
         */
        public string GetCreateSTableSql()
        {
            string colsStr = "";
            int lenSum = 0;

            //加上默认字段
            foreach (int key in columnsDft.Keys)
            {
                colsStr = colsStr + ("".Equals(colsStr) ? "" : ",") + columnsDft[key].columnNameTaos + " " +
                    columnsDft[key].columnType + (("BINARY".Equals(columnsDft[key].columnType) || "NCHAR".Equals(columnsDft[key].columnType)) ? "(" + columnsDft[key].columnLen.ToString() + ")" : "");
                lenSum += columnsDft[key].columnLen;
            }

            //20210527屏蔽 创建表语句太长了，至少再本地docker里面都是执行超时或失败的
            //数据字段
            //表的每行长度不能超过 16k 个字符
            //foreach (int key in columns.Keys)
            //{
            //    if (!columns[key].isParent)
            //    { 
            //        //使用数据类型 binary 或 nchar，需指定其最长的字节数
            //        //字段长度建议不超过2000
            //        colsStr = colsStr + ("".Equals(colsStr) ? "" : ",") + columns[key].columnNameTaos + " " +
            //            columns[key].columnType + (("BINARY".Equals(columns[key].columnType) || "NCHAR".Equals(columns[key].columnType)) ? "(" + columns[key].columnLen.ToString() + ")" : "");
            //        lenSum += columns[key].columnLen;
            //    }
            //}

            //超级表
            string sql = "CREATE STABLE IF NOT EXISTS " + tableName + "(" + colsStr + ") TAGS(ip NCHAR(20), port int)";
            return sql;
        }
    }
}
